﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using DAMS.Data;
using DAMS.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;

namespace DAMS.Service
{
    public class Repository : IRepository
    {
        #region Public
        private readonly DbCon _Db;
        private readonly IMemoryCache _Cache;
        IEnumerable<Category> _categorys;
        string[] _CacheKeys = { "CategoryTop", "CategoryJson_1", "CategoryTemplateJson" };
        public Repository(DbCon dbCon, IMemoryCache memoryCache)
        {
            this._Db = dbCon;
            this._Cache = memoryCache;
        }
        #endregion
        #region Category 

        /// <summary>
        /// 创建一个分类
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public Result<Category> CategoryCreate(Category entity)
        {
            Category ParentEntity = CategoryGetByID(entity.ParentID);//获取父分类


            Result<Category> result = new Result<Category>();//创建返回
            entity.Layer = ParentEntity.Layer + 1;//设置层级，根据父分类层级进行设置
            int mark = ParentEntity.RightNum;
            // 更新左值大于父分类右值的所有分类的左右值
            IEnumerable<Category> upLeft = _Db.Categorys.Where(x => x.LeftNum > mark).ToList();
            foreach (Category item in upLeft)
            {
                item.LeftNum += 2;
            }
            IEnumerable<Category> upRight = _Db.Categorys.Where(x => x.RightNum >= mark).ToList();
            foreach (Category item in upRight)
            {
                item.RightNum += 2;
            }

            //获取左值
            entity.LeftNum = mark;
            entity.RightNum = mark + 1;


            _Db.Categorys.AddAsync(entity);

            int upCount = _Db.SaveChanges();
            ClearCache("Category");//数据变动后清理缓存
            result.Target = entity;
            result.Succeeded = true;
            result.SucceededMsg = $"添加分类:{entity.Name}成功,ID:{entity.ID},ParentID:{entity.ParentID},LeftNum:{entity.LeftNum},RightNum:{entity.RightNum}.受影响记录数：{upCount}";
            return result;
        }
        /// <summary>
        /// 根据ID删除一个分类
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Result<Category> CategoryDeleteByID(int id)
        {
            Category entity = CategoryGetByID(id);
            Result<Category> result = new Result<Category>();
            if (entity == null)//找不到分类的错误
            {
                result.Error.Add("删除一个不存在的分类");
                result.Succeeded = false;
                return result;
            }
            if (entity.RightNum - entity.LeftNum != 1)
            {
                result.Error.Add("要删除的分类下还有子分类，请先删除子分类");
                result.Succeeded = false;
                return result;
            }
            IEnumerable<Category> upLeft = _Db.Categorys.Where(x => x.DeleteFlag == false && x.LeftNum > entity.LeftNum).ToList();
            foreach (Category item in upLeft)
            {
                item.LeftNum -= 2;
            }
            IEnumerable<Category> upRight = _Db.Categorys.Where(x => x.DeleteFlag == false && x.RightNum > entity.RightNum).ToList();
            foreach (Category item in upRight)
            {
                item.RightNum -= 2;
            }
            entity.DeleteFlag = true;
            int upCount = _Db.SaveChanges();//删除，并返回受影响的记录
            result.Succeeded = true;
            result.SucceededMsg = $"删除分类完成{upCount}条记录受到影响;";
            ClearCache("Category");//数据变动后清理缓存
            return result;
        }
        /// <summary>
        /// 创建一个新分类
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public Result<Category> CategoryUpdate(Category entity)
        {
            Result<Category> result = new Result<Category>();
            _Db.Categorys.Update(entity);
            _Db.SaveChanges();
            result.Succeeded = true;
            return result;
        }
        /// <summary>
        /// 更新一个分类
        /// </summary>
        /// <param name="id">分类ID</param>
        /// <param name="name">分类名</param>
        /// <param name="template">模版或Url</param>
        /// <param name="articleTemplate">内容页模版</param>
        /// <param name="desc">Html页面描述</param>
        /// <param name="keyword">Html页面关键字</param>
        /// <param name="content">内容</param>
        /// <param name="showtype">显示位置</param>
        /// <returns>返回结果，指示是否更新成功</returns>
        public Result<Category> CategoryUpdate(int id, string name, string template, string articleTemplate, string desc, string keyword, string content, int showtype)
        {
            Result<Category> result = new Result<Category>();
            //顶级分类或ID为0的情况
            if (id <2)
            {
                result.Succeeded = false;
                result.Error.Add(id == 1 ? "不能更改顶级分类" : "不存在的分类");
                return result;
            }
            Category entity = CategoryGetByID(id);
            if(entity==null)
            {
                result.Succeeded = false;
                result.Error.Add("不存在的分类");
                return result;
            }
            entity.Name = name;
            entity.Template = template;
            entity.ArticleTemplate = articleTemplate;
            entity.HtmlDescription = desc;
            entity.HtmlKeyWord = keyword;
            entity.Content = content;
            entity.ShowType = showtype;
            _Db.Categorys.Update(entity);
            int upCount=_Db.SaveChanges();
            if(upCount==0)
            {
                result.Succeeded = false;
                result.Error.Add("更新失败");
                return result;
            }
            result.Succeeded = true;
            result.SucceededMsg = $"更新成功!{upCount}条记录受到影响";
            return result;
        }
        /// <summary>
        /// 获取全部分类
        /// </summary>
        /// <returns></returns>
        public IEnumerable<Category> CategoryGetAll()
        {
            return _Db.Categorys.Where(x=>x.DeleteFlag==false).OrderBy(x=>x.LeftNum).ToList();
        }
        public Category CategoryMapGetAll()
        {
            IEnumerable<Category> list = _Db.Categorys.Where(x => x.DeleteFlag == false).OrderBy(x => x.LeftNum).ToList();
            foreach (Category item in list)
            {
                //映射父分类
                if (item.ParentID != 0)
                {
                    item.Parent = list.Single(x => x.ID == item.ParentID);
                }
                item.Children=list.Where(x => x.ParentID == item.ID).ToList();
            }
            return list.Single(x=>x.ParentID==0);
        }
        /// <summary>
        /// 获取全部分类的精简形式
        /// </summary>
        /// <returns></returns>
        public CategoryCut CategoryCutGetAll()
        {
            IEnumerable<CategoryCut> list = _Db.Categorys.Where(x => x.DeleteFlag == false).OrderBy(x => x.LeftNum).Select(item => new CategoryCut() { ID = item.ID, ParentID = item.ParentID, Name = item.Name }).ToList();
            foreach (CategoryCut item in list)
            {
                item.Children.AddRange(list.Where(x => x.ParentID == item.ID).ToList());
            }
            return list.Single(x => x.ParentID == 0);
        }
        public string CategoryCutGetJson()
        {
            string json;
            if (!_Cache.TryGetValue("CategoryCutJson_1", out json))
            {
                IEnumerable<CategoryCut> list = _Db.Categorys.Where(x => x.DeleteFlag == false).OrderBy(x => x.LeftNum).Select(item => new CategoryCut() { ID = item.ID, ParentID = item.ParentID, Name = item.Name }).ToList();
                json=JsonConvert.SerializeObject(list);
                _Cache.Set("CategoryCutJson_1", json);
            }
            return json;
        }
        /// <summary>
        /// 获取分类的json数据
        /// </summary>
        /// <param name="pairs">{ { "ID", "id" }, { "Name", "name" } }项，第一个是属性名，第二个要转换成的json属性</param>
        /// <returns></returns>
        public string CategoryGetTreeJson(Dictionary<string, string> pairs)
        {
            // 序列化设置
            JsonSerializerSettings PropSettings = new JsonSerializerSettings
            {
                ContractResolver = new PropsContractResolver(pairs)
            };
           return  JsonConvert.SerializeObject(CategoryGetTree(), Formatting.None, PropSettings);
        }
        /// <summary>
        /// 获取分类的json数据,默认获取{ { "ID", "id" }, { "Name", "name" }, { "Children", "children" } }项，第一个是属性，第二个要转换成的json属性
        /// </summary>
        /// <returns></returns>
        public string CategoryGetTreeJson()
        {
            string json;
            if (!_Cache.TryGetValue("CategoryJson_1", out json))
            {
                Dictionary<string, string> pairs = new Dictionary<string, string> { { "ID", "id" }, { "Name", "name" },{"Type","type" }, { "Children", "children" } };
                json = CategoryGetTreeJson(pairs);
                _Cache.Set("CategoryJson_1", json);
            }
            return json;
        }
        /// <summary>
        /// 获取模板列表
        /// </summary>
        /// <param name="contentRootPath">项目目录</param>
        /// <returns>json字符串</returns>
        public string CategoryGetTemplateJson(string contentRootPath)
        {
            string json;
            if(!_Cache.TryGetValue("CategoryTemplateJson",out json))
            {
                string path = System.IO.Path.Combine(contentRootPath, "Views\\Home");
                IEnumerable<string> files = System.IO.Directory.EnumerateFiles(path, "*.cshtml");
                files=files.Select(x => System.IO.Path.GetFileNameWithoutExtension(x)).ToArray();
                string[] ListTemplates= files.Where(x=>x.StartsWith("List")).ToArray();
                string[] ArticleTemplates = files.Where(x => x.StartsWith("Article")).ToArray();
                string[] PageTemplates = files.Where(x => x.StartsWith("Page")).ToArray();
                string[] HomeTemplates = files.Where(x => x.StartsWith("Index")).ToArray();
                var templates = new { list = ListTemplates, article = ArticleTemplates, page = PageTemplates ,home=HomeTemplates};
                json=JsonConvert.SerializeObject(templates);
                _Cache.Set("CategoryTemplateJson", json);
            }
            return json;
        }
        /// <summary>
        /// 获取分类的树形表示。
        /// </summary>
        /// <returns></returns>
        public Category CategoryGetTree()
        {
            IEnumerable<Category> list = _Db.Categorys.Where(x => x.DeleteFlag == false).OrderBy(x => x.LeftNum).ToList();
            foreach (Category item in list)
            {
                List<Category> temp = list.Where(x => x.ParentID == item.ID).ToList();
                item.Children = temp.Count() > 0 ? temp : null;
            }
            return list.Single(x => x.ParentID == 0);
        }
        /// <summary>
        /// 根据ID获取分类
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Category CategoryGetByID(int id)
        {
            //return Categorys.SingleOrDefault(x => x.ID == id);
            return _Db.Categorys.Single(x => x.ID == id);
        }
        /// <summary>
        /// 根据ID获取分类的全部祖先分类列表
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public IEnumerable<Category> CategoryGetParentListByID(int id)
        {
            Category entity = CategoryGetByID(id);
            return _Db.Categorys.Where(x => x.DeleteFlag == false && x.LeftNum < entity.LeftNum && x.RightNum > entity.RightNum).OrderBy(x => x.LeftNum).ToList();
        }
        /// <summary>
        /// 获取顶层分类
        /// </summary>
        /// <returns></returns>
        public IEnumerable<Category> CategoryGetTop()
        {
            return _Db.Categorys.Where(x => x.DeleteFlag == false && x.Layer == 1).OrderBy(x => x.LeftNum).ToList();
        }
        /// <summary>
        /// 根据id获取子分类
        /// </summary>
        /// <param name="id"></param>
        /// <param name="isInThis">获取的自分类列表是否包含当前分类，默认包含</param>
        /// <param name="isAll">一个布尔值，指示是否获取全部子分类，False将只获取下一级子分类，默认为True</param>
        /// <returns></returns>
        public IEnumerable<Category> CategoryGetChildListByID(int id,bool isInThis=true,bool isAll=true)
        {
            Category entity = CategoryGetByID(id);
            if(isInThis)
            {
                if(isAll)
                    return _Db.Categorys.Where(x => x.DeleteFlag == false && x.LeftNum >= entity.LeftNum && x.RightNum <= entity.RightNum).OrderBy(x => x.LeftNum).ToList();
                else
                    return _Db.Categorys.Where(x => x.DeleteFlag == false && x.LeftNum >= entity.LeftNum && x.RightNum <= entity.RightNum && x.Layer==entity.Layer+1).OrderBy(x => x.LeftNum).ToList();
            }
            else
            {
                if (isAll)
                    return _Db.Categorys.Where(x => x.DeleteFlag == false && x.LeftNum > entity.LeftNum && x.RightNum < entity.RightNum).OrderBy(x => x.LeftNum).ToList();
                else
                    return _Db.Categorys.Where(x => x.DeleteFlag == false && x.LeftNum > entity.LeftNum && x.RightNum < entity.RightNum && x.Layer == entity.Layer + 1).OrderBy(x => x.LeftNum).ToList();
            }
        }


        /// <summary>
        /// 改变分类排序位置
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="newOrder"></param>
        /// <returns></returns>
        public Result<Category> CategoryOrderMove(Category entity, int newOrder)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 改变分类排序位置
        /// </summary>
        /// <param name="id"></param>
        /// <param name="newOrder"></param>
        /// <returns></returns>
        public Result<Category> CategoryOrderMove(int id, int newOrder)
        {
            throw new NotImplementedException();
        }


        /// <summary>
        /// 根据id获取分类的父分类
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Category CategoryGetParentByID(int id)
        {
            Category entity = CategoryGetByID(id);
            if (entity != null)
            {
                if (entity.Parent != null)
                    return entity.Parent;
            }
            return null;
        }

        /// <summary>
        /// 移动分类在兄弟分类中的排序位置
        /// </summary>
        /// <param name="id">要移动的分类ID</param>
        /// <param name="newid">将要移动到新位置所处的分类ID</param>
        /// <returns>返回操作是否成功，及受影响的记录数</returns>
        public Result<Category> CategoryMove(int id, int newid)
        {
            Result<Category> result = new Result<Category>();
            if(id==newid)
            {
                result.Succeeded = true;
                result.SucceededMsg = "移动操作完成，0行记录受影响";
                return result;
            }
            IEnumerable<Category> currList = CategoryGetChildListByID(id);//获取当前分类及子分类--向上移动列表
            Category currEntity = currList.Single(x => x.ID == id);
            Category targetEntity = CategoryGetByID(newid);
            if(currEntity.ParentID!=targetEntity.ParentID)
            {
                result.Succeeded = false;
                result.Error.Add("位置移动只能在兄弟分类间进行操作");
                return result;
            }
            // 移动方向
            if(currEntity.LeftNum>targetEntity.LeftNum)
            {
                //当前分类向上移动
                int upNum = currEntity.LeftNum - targetEntity.LeftNum;//往上移动数量
                int downNum = (currEntity.RightNum - upNum) - targetEntity.LeftNum + 1;//向下移动数量
                List<Category> targetList = _Db.Categorys.Where(x => x.LeftNum >= targetEntity.LeftNum && x.LeftNum < currEntity.LeftNum && x.DeleteFlag == false).OrderBy(x => x.LeftNum).ToList();//获取目标分类及子分类 --向下移动列表
                targetList.ForEach(x => { x.LeftNum += downNum; x.RightNum += downNum; });//将
                // string sql = $"update categorys LeftNum=LeftNum+{upNum},RightNum=RightNum+{upNum} Where ((DeleteFlag=0) and (LeftNum>={targetEntity.LeftNum}))";
                
                foreach (Category item in currList)
                {
                    item.LeftNum -= upNum;
                    item.RightNum -= upNum;
                }
            }
            else
            {
                List<Category> targetList = _Db.Categorys.Where(x => x.LeftNum > currEntity.RightNum && x.LeftNum <= targetEntity.LeftNum && x.DeleteFlag == false).OrderBy(x => x.LeftNum).ToList();//获取目标分类及子分类 --向下移动列表
                
                //当前分类向下移动
                int upNum =targetList[0].LeftNum- currEntity.LeftNum;//向上移动数量
                int downNum = targetEntity.RightNum-upNum+1-currEntity.LeftNum;//向下移动数量
                
                targetList.ForEach(x => { x.LeftNum -= upNum; x.RightNum -= upNum; });//将
                foreach (Category item in currList)
                {
                    item.LeftNum += downNum;
                    item.RightNum += downNum;
                }
            }

            _Db.SaveChanges();
            result.Succeeded = true;
            ClearCache("Category");//数据变动后清理缓存
            return result;
        }

        #region Category private

        //只读属性：从缓存中获取全部分类，并进行分类父子映射。
        private IEnumerable<Category> Categorys
        {
            get
            {
                if (!_Cache.TryGetValue<IEnumerable<Category>>("CategroyTop", out _categorys))
                {
                    _categorys = CategoryMap(_Db.Categorys.Where(x => x.DeleteFlag == false).OrderBy(x => x.LeftNum).ToList());
                    _Cache.Set<IEnumerable<Category>>("CategroyTop", _categorys);
                }
                return _categorys;
            }
        }
        /// <summary>
        /// 清理缓存，通过键名清理，支持匹配开始字符。
        /// </summary>
        /// <param name="cacheName">缓存键名开始字符，如CategoryTreeJson，只需Category即可，所有Category缓存全部清理</param>
        private void ClearCache(string cacheName)
        {
            string[] keys= _CacheKeys.Where(x => x.StartsWith(cacheName)).ToArray();
            foreach(string key in keys)
                _Cache.Remove(key);
                
        }

        /// <summary>
        /// 将分类进行父子映射；
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        private IEnumerable<Category> CategoryMap(IEnumerable<Category> list)
        {
           
            foreach (Category item in list)
            {
                //映射父分类
                if (item.ParentID != 0)
                {
                    item.Parent = list.Single(x => x.ID== item.ParentID);
                }
                item.Children=list.Where(x => x.ParentID == item.ID).ToList();
            }
            return list;

        }

        #endregion
        #endregion

        #region Tag
        /// <summary>
        /// 添加新标签
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        public Result<Tag> TagCreate(Tag tag)
        {
            Result<Tag> result = new Result<Tag>();
            //是否已经有重复的
            if(_Db.Tags.SingleOrDefault(t => t.TagName == tag.TagName)==null)
            {
                _Db.Tags.Add(tag);
                int upCount = _Db.SaveChanges();
                result.Target = tag;
                result.Succeeded = true;
            }
            else
            {
                result.Succeeded = false;
                result.Error.Add($"添加重复的标签:{tag.TagName}");
            }
            return result;
        }
        public Result<Tag> TagUpdate(Tag tag)
        {
            Result<Tag> result = new Result<Tag>();
            if(_Db.Tags.SingleOrDefault(t => t.TagName == tag.TagName) == null)
            {
                _Db.Tags.Update(tag);
                int upCount = _Db.SaveChanges();
                result.Target = tag;
                result.Succeeded = true;
                result.SucceededMsg = $"更新标签成功，{upCount}记录受影响";
            }
            else
            {
                result.Succeeded = false;
                result.SucceededMsg = $"更新标签失败，{tag.TagName} 已存在";
            }
            return result;
        }
        public Result<Tag> TagGet(string name)
        {
            Result<Tag> result = new Result<Tag>();
            Tag tag=  _Db.Tags.SingleOrDefault(x => x.TagName == name);
            if(tag==null)
            {
                result.Succeeded = false;
                result.Error.Add($"不存在{name}的标签");
            }
            else
            {
                result.Succeeded = true;
                result.Target = tag;
            }
            return result;
        }
        public IEnumerable<Tag> TagGetListByPage(int page,int pagesize,string keyword="")
        {
            if(!string.IsNullOrEmpty(keyword))
            {
                return _Db.Tags.Where(t=>t.TagName.Contains(keyword)).OrderBy(t => t.ID).Skip((page - 1) * pagesize).Take(pagesize).ToList();
            }
            return _Db.Tags.OrderBy(t => t.ID).Skip((page-1) * pagesize).Take(pagesize).ToList();
        }
        public int TagGetCount(string keyword="")
        {
            if (string.IsNullOrEmpty(keyword))
                return _Db.Tags.Count();
            else
                return _Db.Tags.Where(t => t.TagName.Contains(keyword)).Count();

        }
        /// <summary>
        /// 根据ID删除标签
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Result<Tag> TagDeleteByID(int id)
        {
            Tag tag = new Tag() { ID = id };
            _Db.Tags.Remove(tag);
            Result<Tag> result = new Result<Tag>();
            try
            {
                int upCount = _Db.SaveChanges();
                result.Succeeded = true;
                result.Target = tag;
                result.SucceededMsg = $"删除成功{upCount}行记录受影响";
            }
            catch (Exception e)
            {
                result.Succeeded = false;
                result.Target = tag;
                result.SucceededMsg = $"删除失败:{e.Message}";
            }
            return result;
        }
        #endregion
        #region ArticleTag
        public Result<Article> Create(ArticleTag at)
        {
            _Db.Add(at);
            _Db.SaveChanges();
            return new Result<Article>();
        }
        
        #endregion
        #region Article
        /// <summary>
        /// 添加一个内容
        /// </summary>
        /// <param name="article"></param>
        /// <returns></returns>
        public Result<Article> ArticleCreate(Article article)
        {
            Result<Article> result = new Result<Article>();
            _Db.Articles.Add(article);
            try
            {
                _Db.SaveChanges();
                result.Succeeded = true;
            }
            catch (Exception e)
            {
                result.Error.Add($"添加内容发生错误,错误信息:{e.Message}");
            }
            return result;
        }
        /// <summary>
        /// 根据ID获取文章
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Article ArticleGetByID(int id)
        {
            return _Db.Articles.Include(at=>at.ArticleTags).ThenInclude(t=>t.Tag).Single(a => a.ID == id);
        }
        public Result<Article> ArticleUpdate(Article article)
        {
            _Db.Articles.Update(article);
            _Db.SaveChanges();
            return new Result<Article>();
        }

        public List<Article> ArticleGetByPager(int pageIndex,int pageSize, Expression<Func<Article, bool>> lamband=null)
        {
            //MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
            ParameterExpression exps = Expression.Parameter(typeof(Article), "a");
            Expression left = Expression.Property(exps, "DeleteFlag");
            Expression right = Expression.Constant(false);
            Expression exp2 = Expression.Equal(left, right);
            Expression<Func<Article, bool>> lamband1 = Expression.Lambda<Func<Article, bool>>(exp2, exps);
            if (lamband!=null)
            {
                //合并连个lamband表达式
                var invokedExpr = Expression.Invoke(lamband, lamband1.Parameters.Cast<Expression>());
                Expression<Func<Article, bool>> lamband2 = Expression.Lambda<Func<Article, bool>>(Expression.AndAlso(lamband1.Body, invokedExpr), lamband1.Parameters);
                return _Db.Articles.Where(lamband2).OrderByDescending(a => a.PublishTime).Skip(pageSize * (pageIndex - 1)).Take(pageSize).ToList();
            }
            return _Db.Articles.Where(lamband1).OrderByDescending(a => a.PublishTime).Skip(pageSize * (pageIndex - 1)).Take(pageSize).ToList();
        }
        #endregion
    }

    /// <summary>
    /// 反馈结果类，用于指示增删查改操作的结果反馈。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Result<T>
    {
        public Result()
        {
            Error = new List<string>();
        }

        /// <summary>
        /// 完成标记
        /// </summary>
        public bool Succeeded { get; set; }
        /// <summary>
        /// 错误列表
        /// </summary>
        public List<string> Error { get; set; }
        /// <summary>
        /// 成功时反馈的信息
        /// </summary>
        public string SucceededMsg { get; set; }
        /// <summary>
        /// 目标实体
        /// </summary>
        public T Target { get; set; }
    }
}
